﻿#region

using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Vin.Tool.AspNetCore.Singleton;

#endregion

namespace Vin.Extension.Cache;

public class MemoryCache : ICache
{
    private readonly ILogger<MemoryCache> _logger = VinApp.GetRequiredService<ILogger<MemoryCache>>();

    private readonly IMemoryCache _cache = VinApp.GetRequiredService<IMemoryCache>();

    public bool SetCache<T>(string key, T value, TimeSpan? expireTime = null)
    {
        return _cache.Set(key, value, expireTime ?? TimeSpan.Zero) != null;
    }

    public async Task<bool> SetCacheAsync<T>(string key, T value, TimeSpan? expireTime = null)
    {
        return await Task.FromResult(SetCache(key, value, expireTime));
    }

    public async Task<T?> GetCacheAsync<T>(string key)
    {
        return await Task.FromResult(GetCache<T>(key));
    }

    public bool RemoveCache(string key)
    {
        _cache.Remove(key);
        return true;
    }

    public async Task<bool> RemoveCacheAsync(string key)
    {
        return await Task.FromResult(RemoveCache(key));
    }

    public T? GetCache<T>(string key)
    {
        var value = _cache.Get<T>(key);
        return value;
    }

    private Dictionary<string, T> GetHashCache<T>(string key)
    {
        return _cache.GetOrCreate(key, _ => new Dictionary<string, T>())!;
    }

    public bool SetHashCache<T>(string key, string field, T value, TimeSpan? expireTime = null)
    {
        var dict = GetHashCache<T>(key);
        dict[field] = value;
        _cache.Set(key, dict, expireTime ?? TimeSpan.Zero);
        return true;
    }

    public async Task<bool> SetHashCacheAsync<T>(string key, string field, T value, TimeSpan? expireTime = null)
    {
        return await Task.FromResult(SetHashCache(key, field, value, expireTime));
    }

    public T? GetHashCache<T>(string key, string field)
    {
        var dict = GetHashCache<T>(key);
        return dict.TryGetValue(field, out var value) ? value : default;
    }

    public async Task<T?> GetHashCacheAsync<T>(string key, string field)
    {
        return await Task.FromResult(GetHashCache<T>(key, field));
    }

    public bool RemoveHashCache(string key, string field)
    {
        var dict = GetHashCache<object>(key);
        dict.Remove(field);
        return true;
    }

    public async Task<bool> RemoveHashCacheAsync(string key, string field)
    {
        return await Task.FromResult(RemoveHashCache(key, field));
    }

    public long GetHashCount(string key)
    {
        var dict = GetHashCache<object>(key);
        return dict.Count;
    }

    public async Task<long> GetHashCountAsync(string key)
    {
        return await Task.FromResult(GetHashCount(key));
    }

    public long Incr(string key, TimeSpan? expireTime = null, bool firstSetExpire = true)
    {
        var value = _cache.GetOrCreate(key, _ => 0L);
        value++;
        if(value == 1 && firstSetExpire)
        {
            _cache.Set(key, value, expireTime ?? TimeSpan.Zero);
        }
        return value;
    }

    public async Task<long> IncrAsync(string key, TimeSpan? expireTime = null, bool firstSetExpire = true)
    {
        return await Task.FromResult(Incr(key, expireTime, firstSetExpire));
    }
}